import { basename, dirname } from '@tauri-apps/api/path'
import { useSettingStore } from '../stores/setting'
import { getContent } from './file'
import { executeCommand } from './ipc'

export enum CVSStatus {
  UpToDate = 'Up-to-date',
  Modified = 'Modified',
  Added = 'Added',
  LocallyAdded = 'Locally Added',
  Removed = 'Removed',
  Conflict = 'Conflict',
  Unknown = 'Unknown',
  NeedsCheckout = 'Needs Checkout',
  NeedsPatch = 'Needs Patch',
  NeedsMerge = 'Needs Merge',
  UnresolvedConflict = 'Unresolved Conflict',
  LocallyModified = 'Locally Modified'
}

export const CVSStatusText: Record<CVSStatus, string> = {
  [CVSStatus.UpToDate]: '最新',
  [CVSStatus.Modified]: '已修改',
  [CVSStatus.LocallyModified]: '已修改',
  [CVSStatus.Added]: '已添加',
  [CVSStatus.LocallyAdded]: '本地已添加',
  [CVSStatus.Removed]: '已删除',
  [CVSStatus.Conflict]: '冲突',
  [CVSStatus.NeedsPatch]: '需要合并',
  [CVSStatus.NeedsMerge]: '需要合并',
  [CVSStatus.UnresolvedConflict]: '冲突',
  [CVSStatus.Unknown]: '待提交',
  [CVSStatus.NeedsCheckout]: '待检出'
}

export interface CVSFile {
  filename: string
  status: string // 文件状态
  rawStatus: string // 文件状态
  workingVersion: string // 工作版本
  repositoryVersion: string // 仓库版本
  tags: CVSTag[] // 标签列表
}

export interface CVSTag {
  name: string
  revision: string
}

export class NotCVSFileError extends Error {
  constructor() {
    super('非CVS文件')
    this.name = 'NotCVSFileError'
  }
}

function getCvsCommand(): string {
  const settingStore = useSettingStore()
  return settingStore.cvsPath || 'cvs'
}

/**
 * 获取指定tag的文件内容
 * @param filepath
 * @param tag
 */
export async function cvsGetTagFile(filepath: string, tag: string): Promise<string> {
  try {
    const dir = await dirname(filepath)
    const filename = await basename(filepath)
    const repository = (await getContent(`${dir}/CVS/Repository`))?.trim()
    const cvsPath = `${repository}/${filename}`
    await executeCommand(getCvsCommand(), ['-q', 'checkout', '-r', tag, '-d', 'temp', `${cvsPath}`], dir)
    const content = await getContent(`${dir}/temp/${filename}`)
    await executeCommand(getCvsCommand(), ['remove', '-f', `${dir}/temp/${filename}`], dir)
    return content
  } catch (error: any) {
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
}

export async function cvsStatus(filepath: string): Promise<CVSFile> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  let result: string
  try {
    result = await executeCommand(getCvsCommand(), ['status', '-v', base], dir)
    console.log(result)
  } catch (error: any) {
    if (typeof error === 'string' && error.includes('No CVSROOT specified!')) {
      throw new NotCVSFileError()
    }
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
  return parseCVSStatus(result)
}

export async function cvsStatusMulti(filepaths: string[]): Promise<CVSFile[]> {
  const results = await executeCvsByDirectory(['status', '-v'], filepaths, { chunkSize: 10 })
  return results
    .map((result) =>
      result
        .split(/^={4,}/m)
        .filter((block) => block.trim())
        .map(parseCVSStatus)
    )
    .flat()
}

function parseCVSStatus(result: string): CVSFile {
  const filename = result.match(/File:\s+(.+?)\s+Status:/m)?.[1].trim()
  const statusMatch = result.match(/File:\s+(.+?)\s+Status:\s+(.+?)$/m)
  const workingMatch = result.match(/Working revision:\s+(\d+(\.\d+)+)/m)
  const repoMatch = result.match(/Repository revision:\s+(\d+(\.\d+)+)/m)

  if (!statusMatch) {
    throw new Error('无法解析 CVS 状态信息')
  }

  let statusText = statusMatch[2].trim()
  if (!CVSStatusText[statusText as CVSStatus]) {
    console.log(`未知的CVS状态: ${statusText}, 尝试转换为 Conflict`)
    statusText = CVSStatus.Conflict
  }
  const workingVersion = workingMatch ? workingMatch[1].trim() : '-'
  const repositoryVersion = repoMatch ? repoMatch[1].trim() : '-'

  const tagsIndex = result.indexOf('Existing Tags:')
  let tags: CVSTag[]
  if (tagsIndex !== -1) {
    tags = result
      .substring(tagsIndex + 15)
      .trim()
      .split('\n')
      .filter((line) => line.trim())
      .map((line) => {
        const tagMatch = line.match(/(.+?)\s+\(revision:\s+(.+?)\)/)
        return {
          name: tagMatch ? tagMatch[1].trim() : '',
          revision: tagMatch ? tagMatch[2].trim() : ''
        }
      })
      .filter((tag) => tag.name && tag.revision)
  } else {
    tags = []
  }
  return {
    filename: filename || '',
    status: CVSStatusText[statusText as CVSStatus] || statusText,
    rawStatus: statusText as CVSStatus,
    workingVersion,
    repositoryVersion,
    tags
  }
}

export async function cvsUpdate(filepath: string): Promise<string> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  let result: string
  try {
    result = await executeCommand(getCvsCommand(), ['update', base], dir)
    return result
  } catch (error: any) {
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
}

/**
 * CVS合并处理：处理需要合并的文件
 * @param filepath 文件路径
 * @returns 合并结果信息
 */
export async function cvsMerge(filepath: string): Promise<{
  success: boolean
  hasConflicts: boolean
  message: string
}> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)

  try {
    // 执行CVS更新，这会自动尝试合并
    const result = await executeCommand(getCvsCommand(), ['update', base], dir)

    // 检查合并结果
    if (result.includes('conflicts during merge')) {
      return {
        success: false,
        hasConflicts: true,
        message: '合并过程中发现冲突，需要手动解决'
      }
    } else if (result.includes('merged')) {
      return {
        success: true,
        hasConflicts: false,
        message: '文件已成功自动合并'
      }
    } else {
      return {
        success: true,
        hasConflicts: false,
        message: '文件已更新到最新版本'
      }
    }
  } catch (error: any) {
    return {
      success: false,
      hasConflicts: false,
      message: `合并失败: ${error?.message || error}`
    }
  }
}

export async function cvsAdd(filepath: string): Promise<string> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  let result: string
  try {
    result = await executeCommand(getCvsCommand(), ['add', base], dir)
    return result
  } catch (error: any) {
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
}

export async function cvsCommit(filepath: string, message: string): Promise<string> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  let result: string
  try {
    result = await executeCommand(getCvsCommand(), ['commit', '-m', message, base], dir)
    return result
  } catch (error: any) {
    const errorMessage = error?.message || error

    // 检查是否是Up-to-date check failed错误
    if (typeof errorMessage === 'string' && errorMessage.includes('Up-to-date check failed')) {
      throw new Error(`"文件需要更新后才能提交。请先执行更新操作：${errorMessage}"`)
    }

    throw new Error(`"执行CVS命令失败, ${errorMessage}"`)
  }
}

/**
 * 预提交检查：检查文件是否可以安全提交
 * @param filepath 文件路径
 * @returns 检查结果和建议操作
 */
export async function cvsPreCommitCheck(filepath: string): Promise<{
  canCommit: boolean
  needsUpdate: boolean
  hasConflict: boolean
  status: CVSFile
  suggestion: string
}> {
  try {
    const status = await cvsStatus(filepath)

    const result = {
      canCommit: false,
      needsUpdate: false,
      hasConflict: false,
      status,
      suggestion: ''
    }

    switch (status.rawStatus) {
      case CVSStatus.UpToDate:
        result.suggestion = '文件已是最新版本，无需提交'
        break
      case CVSStatus.Modified:
      case CVSStatus.LocallyModified:
        result.canCommit = true
        result.suggestion = '文件可以直接提交'
        break
      case CVSStatus.Added:
      case CVSStatus.LocallyAdded:
        result.canCommit = true
        result.suggestion = '新添加的文件，可以直接提交'
        break
      case CVSStatus.Conflict:
      case CVSStatus.UnresolvedConflict:
        result.hasConflict = true
        result.suggestion = '文件存在冲突，需要先解决冲突'
        break
      case CVSStatus.NeedsMerge:
        result.needsUpdate = true
        result.hasConflict = true
        result.suggestion = '文件需要合并，建议先更新文件然后手动解决冲突'
        break
      case CVSStatus.NeedsCheckout:
      case CVSStatus.NeedsPatch:
        result.needsUpdate = true
        result.suggestion = '文件需要先更新到最新版本'
        break
      case CVSStatus.Unknown:
        result.canCommit = true
        result.suggestion = '新文件，需要先添加到CVS'
        break
      default:
        result.suggestion = `未知状态: ${status.rawStatus}`
    }

    return result
  } catch (error: any) {
    throw new Error(`"预提交检查失败: ${error?.message || error}"`)
  }
}

/**
 * 智能提交函数：自动处理Up-to-date检查失败的情况
 * @param filepath 文件路径
 * @param message 提交消息
 * @param autoUpdate 是否自动更新文件（默认为true）
 * @returns 提交结果
 */
export async function cvsCommitSmart(filepath: string, message: string, autoUpdate: boolean = true): Promise<string> {
  try {
    // 预提交检查
    const checkResult = await cvsPreCommitCheck(filepath)

    if (checkResult.needsUpdate && autoUpdate) {
      console.log(`文件需要更新，正在处理: ${filepath}`)

      // 检查是否是需要合并的状态
      if (checkResult.status.rawStatus === CVSStatus.NeedsMerge) {
        console.log(`文件需要合并，尝试自动合并: ${filepath}`)
        const mergeResult = await cvsMerge(filepath)

        if (!mergeResult.success || mergeResult.hasConflicts) {
          throw new Error(`"${mergeResult.message}"`)
        }

        console.log(`合并成功: ${mergeResult.message}`)
      } else {
        await cvsUpdate(filepath)
      }
    } else if (checkResult.hasConflict && !checkResult.needsUpdate) {
      // 纯冲突状态，无法自动处理
      throw new Error(`"文件存在冲突，无法提交: ${checkResult.suggestion}"`)
    }

    // 尝试提交
    return await cvsCommit(filepath, message)
  } catch (error: any) {
    const errorMessage = error?.message || error

    // 如果是Up-to-date check failed错误且允许自动更新
    if (autoUpdate && typeof errorMessage === 'string' && errorMessage.includes('Up-to-date check failed')) {
      console.log(`检测到文件需要更新，正在自动更新: ${filepath}`)

      try {
        // 先更新文件
        await cvsUpdate(filepath)

        // 再次尝试提交
        return await cvsCommit(filepath, message)
      } catch (updateError: any) {
        throw new Error(`"自动更新后提交失败: ${updateError?.message || updateError}"`)
      }
    }

    // 其他错误直接抛出
    throw error
  }
}

export async function cvsTag(filepath: string, tag: string): Promise<void> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  try {
    await executeCommand(getCvsCommand(), ['tag', '-F', tag, base], dir)
  } catch (error: any) {
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
}

export async function cvsRemoveTag(filepath: string, tag: string): Promise<void> {
  const dir = await dirname(filepath)
  const base = await basename(filepath)
  try {
    await executeCommand(getCvsCommand(), ['tag', '-d', tag, base], dir)
  } catch (error: any) {
    throw new Error(`"执行CVS命令失败, ${error?.message || error}"`)
  }
}

export async function cvsTagMulti(filepaths: string[], tag: string): Promise<void> {
  await executeCvsByDirectory(['tag', '-F', tag], filepaths)
}

export async function cvsHistory(filepath: string | string[]): Promise<string> {
  const filepaths = Array.isArray(filepath) ? filepath : [filepath]
  const result = await executeCvsByDirectory(['history', '-clwf'], filepaths)
  return result
    .join('\n')
    .split('\n')
    .filter((line) => line.trim() !== '')
    .join('\n')
    .trim()
}

function chunkArray<T>(items: T[], chunkSize?: number): T[][] {
  if (!chunkSize || chunkSize <= 0 || chunkSize === Infinity) {
    return items.length ? [items] : []
  }

  const result: T[][] = []
  for (let index = 0; index < items.length; index += chunkSize) {
    result.push(items.slice(index, index + chunkSize))
  }
  return result
}

async function executeCvsByDirectory<T>(
  args: string[],
  filepaths: string[],
  options?: { chunkSize?: number }
): Promise<string[]> {
  const fileInfos = await Promise.all(
    filepaths.map(async (fp) => ({
      dir: await dirname(fp),
      base: await basename(fp),
      originalPath: fp
    }))
  )

  const dirGroups = fileInfos.reduce(
    (acc, { dir, base, originalPath }) => {
      const key = dir
      if (!acc[key]) {
        acc[key] = { dir, files: [] }
      }
      acc[key].files.push({ base, originalPath })
      return acc
    },
    {} as Record<string, { dir: string; files: { base: string; originalPath: string }[] }>
  )

  try {
    const chunkSize = options?.chunkSize
    const commandPromises = Object.values(dirGroups).flatMap(({ dir, files }) => {
      const fileNames = files.map((f) => f.base)
      const chunks = chunkArray(fileNames, chunkSize)
      return chunks.filter((chunk) => chunk.length > 0).map((chunk) => {
        const realArgs = [...args, ...chunk]
        return executeCommand(getCvsCommand(), realArgs, dir)
      })
    })
    return await Promise.all(commandPromises)
  } catch (error: any) {
    console.log('执行CVS命令失败:', error)
    throw new Error(`执行CVS命令失败, ${error?.message || error}`)
  }
}
